Skip to content

harden: vector security audit fixes - #115

Merged
kacy merged 4 commits into
mainfrom
harden-vector-security
Feb 14, 2026
Merged

harden: vector security audit fixes#115
kacy merged 4 commits into
mainfrom
harden-vector-security

Conversation

@kacy

@kacy kacy commented Feb 14, 2026

Copy link
Copy Markdown
Owner

summary

security audit of the vector similarity search code (HNSW via usearch, PRs #95-96) identified the likely root cause of the VM OOM/hang and several other vulnerabilities across all crates.

root cause of OOM: VSIM's COUNT and EF parameters accepted unbounded u64 values. a single VSIM key 0.1 COUNT 999999999999 request could exhaust all available memory.

fixes by crate

ember-protocol

  • cap VSIM COUNT to 10,000 (MAX_VSIM_COUNT)
  • cap VSIM EF to 1,024 (MAX_VSIM_EF, consistent with VADD)
  • 21 new vector command parser tests

emberkv-core

  • replace unreachable!() in vrem with proper error return
  • use saturating arithmetic in vadd memory estimate (prevents overflow bypassing memory limits)
  • use saturating_mul in VectorSet::memory_usage()
  • improve VectorSet::clone fallback chain with intermediate layers before last-resort panic
  • guard search result consistency

ember-persistence

  • reject AOF records with dim > 65,536 (MAX_PERSISTED_VECTOR_DIMS)
  • reject snapshot entries with dim or count exceeding limits
  • validate metric/quantization enum values on deserialization
  • add FormatError::InvalidData variant

what was tested

  • all 329 unit tests pass (21 new vector command tests)
  • cargo clippy clean
  • cargo fmt clean
  • cargo audit clean (no CVEs in dependencies)

design considerations

the VSIM COUNT cap of 10,000 is generous for any practical similarity search (most applications use k=10-100). this prevents the OOM vector while not limiting legitimate usage. the persistence caps match the protocol-layer limits for consistency.

kacy added 4 commits February 14, 2026 09:32
VSIM's COUNT and EF_SEARCH parameters accepted unbounded u64 values,
allowing a single request like `VSIM key 0.1 COUNT 999999999999` to
cause immediate OOM by attempting to allocate a massive results vector.

- add MAX_VSIM_COUNT (10,000) — generous for any practical similarity
  search while preventing memory exhaustion
- add MAX_VSIM_EF (1,024) — consistent with VADD's MAX_HNSW_PARAM,
  prevents worst-case O(n) graph traversal
- replace unreachable!() in vrem with proper WrongType error return
- use saturating arithmetic in vadd memory estimate to prevent overflow
  from bypassing memory limits
- use saturating_mul in VectorSet::memory_usage() to prevent overflow
  in tracking calculations
- improve VectorSet::clone fallback chain — adds intermediate fallback
  layers before last-resort panic, with tracing::error logging
- guard search result consistency with min() on key/distance lengths
a crafted AOF or snapshot file could specify dimension=4 billion,
causing the recovery loop to iterate 4B times and exhaust memory
despite capped_capacity limiting the initial allocation.

- add MAX_PERSISTED_VECTOR_DIMS (65,536) and MAX_PERSISTED_VECTOR_COUNT
  (10M) constants in format.rs
- reject AOF records with dim > MAX_PERSISTED_VECTOR_DIMS
- reject snapshot entries with dim or count exceeding limits
- validate metric (0-2) and quantization (0-2) enum values in snapshot
  deserialization to catch corruption early
- add FormatError::InvalidData variant for structured error reporting
21 tests covering VADD, VSIM, VREM, VGET, VCARD, VDIM, VINFO parsing
including edge cases: wrong arity, exceeding limits, unknown options.
@kacy
kacy force-pushed the harden-vector-security branch from 3058f48 to 05820b4 Compare February 14, 2026 14:44
@kacy
kacy merged commit 56e5e79 into main Feb 14, 2026
7 checks passed
@kacy
kacy deleted the harden-vector-security branch February 14, 2026 14:45
kacy added a commit that referenced this pull request Feb 19, 2026
* harden: cap VSIM COUNT and EF parameters

VSIM's COUNT and EF_SEARCH parameters accepted unbounded u64 values,
allowing a single request like `VSIM key 0.1 COUNT 999999999999` to
cause immediate OOM by attempting to allocate a massive results vector.

- add MAX_VSIM_COUNT (10,000) — generous for any practical similarity
  search while preventing memory exhaustion
- add MAX_VSIM_EF (1,024) — consistent with VADD's MAX_HNSW_PARAM,
  prevents worst-case O(n) graph traversal

* harden: fix panics and overflows in vector operations

- replace unreachable!() in vrem with proper WrongType error return
- use saturating arithmetic in vadd memory estimate to prevent overflow
  from bypassing memory limits
- use saturating_mul in VectorSet::memory_usage() to prevent overflow
  in tracking calculations
- improve VectorSet::clone fallback chain — adds intermediate fallback
  layers before last-resort panic, with tracing::error logging
- guard search result consistency with min() on key/distance lengths

* harden: validate vector dimensions and counts in persistence

a crafted AOF or snapshot file could specify dimension=4 billion,
causing the recovery loop to iterate 4B times and exhaust memory
despite capped_capacity limiting the initial allocation.

- add MAX_PERSISTED_VECTOR_DIMS (65,536) and MAX_PERSISTED_VECTOR_COUNT
  (10M) constants in format.rs
- reject AOF records with dim > MAX_PERSISTED_VECTOR_DIMS
- reject snapshot entries with dim or count exceeding limits
- validate metric (0-2) and quantization (0-2) enum values in snapshot
  deserialization to catch corruption early
- add FormatError::InvalidData variant for structured error reporting

* test: add vector command parser tests

21 tests covering VADD, VSIM, VREM, VGET, VCARD, VDIM, VINFO parsing
including edge cases: wrong arity, exceeding limits, unknown options.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant